import { existsSync, readFileSync } from 'fs'
import { load } from 'js-yaml'
import { merge } from 'lodash'
import { isAbsolute, join } from 'path'
import i18n from '@/i18n'
import { Assist, closetDirectory, getNodeEnv } from '@libs/lhy-common'

export class CoreConfigLoader {
  /**
   * 文件后缀
   */
  static readonly FILE_EXTS = ['yaml', 'yml']

  /**
   * 生产环境名称
   */
  static readonly PRODUCTION_ENV = 'production'

  /**
   * 配置文件目录
   */
  static readonly CONFIG_DIRECTORY = 'resource/config'

  /**
   * 加载配置文件
   * @param relativeDirectory 配置文件目录
   * @param option 配置文件加载选项
   */
  static loadConfig<T extends Record<string, any>>(
    relativeDirectory?: string,
    option?: CoreConfigLoaderLoadConfigOption
  ) {
    const productionEnv = option?.productionEnv || this.PRODUCTION_ENV

    relativeDirectory = relativeDirectory ?? (CoreConfigLoader.CONFIG_DIRECTORY as string)
    const anchorDirectory = closetDirectory(__dirname, {
      depth: 3,
      onDirectory: relativeDirectory,
    })
    Assist.threw(
      !anchorDirectory,
      i18n.t('lhy-core.core-config.core-config-loadger.1214817-0', { args: [relativeDirectory] })
    )

    const configDirectory = join(anchorDirectory, relativeDirectory)

    // 加载生产环境配置文件，并将其转换为 T 对象
    const productionConfig = this.loadEnvConfig<T>(configDirectory, productionEnv)
    Assist.threw(
      !productionConfig,
      i18n.t('lhy-core.core-config.core-config-loadger.1214817-1', { args: [productionEnv] })
    )

    // 加载环境配置文件
    const nodeEnv = getNodeEnv()
    if (nodeEnv === productionEnv) {
      return productionConfig
    }

    const nodeEnvConfig = this.loadEnvConfig<Partial<T>>(configDirectory, nodeEnv)

    return nodeEnvConfig ? merge(productionConfig, nodeEnvConfig) : productionConfig
  }

  /**
   * 加载环境配置文件
   * @param directory 配置文件目录
   * @param nodeEnv 环境名称
   */
  static loadEnvConfig<T extends Record<string, any>>(directory: string, nodeEnv: string) {
    directory = isAbsolute(directory) ? directory : join(__dirname, directory)
    for (const ext of CoreConfigLoader.FILE_EXTS) {
      // 获取环境配置文件路径
      const envFilePath = join(directory, `${nodeEnv}.${ext}`)
      // 如果文件存在，则加载配置文件
      if (existsSync(envFilePath)) {
        return load(readFileSync(envFilePath, 'utf-8')) as T
      }
    }

    // 文件不存在，返回 null
    return null
  }
}

export interface CoreConfigLoaderLoadConfigOption {
  /**
   * 生产环境名称
   */
  productionEnv?: string
}
